home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / updates / update18.zoo / libg++ / src / xfix24.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-22  |  8.6 KB  |  353 lines

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /* 
  3. Copyright (C) 1988 Free Software Foundation
  4.     written by Kurt Baudendistel (gt-eedsp!baud@gatech.edu)
  5.     adapted for libg++ by Doug Lea (dl@rocky.oswego.edu)
  6.  
  7. This file is part of the GNU C++ Library.  This library is free
  8. software; you can redistribute it and/or modify it under the terms of
  9. the GNU Library General Public License as published by the Free
  10. Software Foundation; either version 2 of the License, or (at your
  11. option) any later version.  This library is distributed in the hope
  12. that it will be useful, but WITHOUT ANY WARRANTY; without even the
  13. implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  14. PURPOSE.  See the GNU Library General Public License for more details.
  15. You should have received a copy of the GNU Library General Public
  16. License along with this library; if not, write to the Free Software
  17. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */
  19.  
  20. //
  21. // Fix24.cc : fixed precision class support functions
  22. //
  23.  
  24. #ifdef __GNUG__
  25. #pragma implementation
  26. #endif
  27. #include <xfix24.h>
  28.  
  29. // basic operators too large to be inline
  30.  
  31. long Fix24::assign(double d) 
  32.   if (d == 1.0)
  33.     return Fix24_m_max;
  34.   else if (d > Fix24_max)
  35.   {
  36.     long i = Fix24_m_max;
  37.     range_error(i);
  38.     return i;
  39.   }
  40.   else if (d < Fix24_min)
  41.   {
  42.     long i = Fix24_m_min;
  43.     range_error(i);
  44.     return i;
  45.   }
  46.   else {
  47.     d = (long) (d * (1 << 24) + ((d >= 0)? 0.5 : -0.5)); // Round to 24 bits
  48.     return ((long) d) << (Fix24_shift - 24);     /* Convert to integer format */
  49.   }
  50. }
  51.  
  52. twolongs Fix48::assign(double d) 
  53.   if (d == 1.0)
  54.     return Fix48_m_max;
  55.   else if (d > Fix48_max)
  56.   {
  57.     twolongs i = Fix48_m_max;
  58.     range_error(i);
  59.     return i;
  60.   }
  61.   else if (d < Fix48_min)
  62.   {
  63.     twolongs i = Fix48_m_min;
  64.     range_error(i);
  65.     return i;
  66.   }
  67.   else {
  68.     twolongs i;
  69.     int sign = (d < 0);
  70.  
  71. /* First, convert the absolute value of d to a 48-bit integer format */
  72.     if (d < 0) d = -d;
  73.     i.u = ((long)(d *= Fix24_mult)) & 0xffffff00;
  74.     i.l = ((unsigned long)((d - i.u)* (Fix24_mult / (1 << 7)))) & 0xffffff00;
  75.  
  76. /* Calculate the two's complement if d was negative */
  77.     if (sign) {
  78.     unsigned long oldlower = i.l;
  79.     i.l = (~i.l + 1) & 0xffffff00;
  80.     i.u = (~i.u + (((oldlower ^ i.l) & Fix24_msb)? 0 : 1)) & 0xffffff00;
  81.     }
  82.     return i;
  83.   }
  84. }
  85.  
  86.  
  87. Fix48 operator * (Fix24& a, Fix24& b)
  88. {
  89. // break a and b into lo and hi parts, and do a multiple-precision
  90. // multiply, with rounding
  91.  
  92.   int apos = (a.m >= 0);
  93.   unsigned long ua = (apos)? a.m : - a.m;
  94.   ua <<= 1; // ua is biased so result will be 47 bit mantissa, not 46:
  95.   unsigned long hi_a = (ua >> 16) & ((1 << 16) - 1);
  96.   unsigned long lo_a = ua & ((1 << 16) - 1);
  97.  
  98.   int bpos = (b.m >= 0);
  99.   unsigned long ub = (bpos)? b.m : -b.m;
  100.   unsigned long hi_b = (ub >> 16) & ((1 << 16) - 1);
  101.   unsigned long lo_b = ub & ((1 << 16) - 1);
  102.  
  103.   unsigned long 
  104.     hi_r = hi_a * hi_b,
  105.     mi_r = hi_a * lo_b + lo_a * hi_b,
  106.     lo_r = lo_a * lo_b,
  107.     rl = ((hi_r << 16) & 0x00ffffffL) + (mi_r & 0x00ffffffL) + (lo_r >> 16);
  108.   twolongs r;
  109.   r.u = (hi_r & 0xffffff00L) + ((mi_r >> 16) & 0x0000ff00L)
  110.     + ((rl >> 16) & 0x0000ff00L);
  111.   r.l = rl << 8;
  112.  
  113.   if ( apos != bpos ) {
  114.     unsigned long l = r.l;
  115.     r.l = -r.l;
  116.     r.u = (~r.u + ((l ^ r.l) & Fix24_msb ? 0 : Fix24_lsb)) & 0xffffff00;
  117.   }
  118.   return r;
  119. }
  120.  
  121. Fix24 operator / (Fix24& a, Fix24& b)
  122. {
  123.   long q;
  124.   int apos = (a.m >= 0);
  125.   unsigned long la = (apos)? a.m : -a.m;
  126.   int bpos = (b.m >= 0);
  127.   unsigned long lb = (bpos)? b.m: -b.m;
  128.   if (la >= lb)
  129.   {
  130.     q = (apos == bpos)? Fix24_m_max: Fix24_m_min;
  131.     a.range_error(q);
  132.   }
  133.   else                        // standard shift-based division alg
  134.   {
  135.     q = 0;
  136.     long r = la;
  137.  
  138.     for (int i = 32; i > 0; i--)
  139.     {
  140.     if ((unsigned long)(r) > lb) {
  141.         q = (q << 1) | 1;
  142.         r -= lb;
  143.     }
  144.     else
  145.         q = (q << 1);
  146.     r <<= 1;
  147.     }
  148.  
  149.     q += 0x80;            // Round result to 24 bits
  150.     if (apos != bpos) q = -q;    // Fix sign
  151.   }
  152.   return (q & 0xffffff00);
  153. }
  154.  
  155.  
  156. Fix48 operator + (Fix48&  f, Fix48&  g)
  157. {
  158.   long lo_r = (f.m.l >> 8) + (g.m.l >> 8);
  159.   twolongs r;
  160.   r.u = f.m.u + g.m.u + (lo_r & 0x01000000L ? 0x00000100L : 0);
  161.   r.l =  lo_r << 8;
  162.  
  163.   if ( (f.m.u ^ r.u) & (g.m.u ^ r.u) & Fix24_msb )
  164.     f.overflow(r);
  165.   return r;
  166. }
  167.  
  168. Fix48 operator - (Fix48&  f, Fix48&  g)
  169. {
  170.   unsigned lo_r = (f.m.l >> 8) - (g.m.l >> 8);
  171.   twolongs r;
  172.   r.u = f.m.u - g.m.u - (lo_r & 0x01000000L ? 0x00000100L: 0);
  173.   r.l = lo_r << 8;
  174.  
  175.   if ( ((f.m.u ^ r.u) & (-g.m.u ^ r.u) & Fix24_msb) && g.m.u )
  176.     f.overflow(r);
  177.   return r;
  178. }
  179.  
  180. Fix48 operator * (Fix48& a, long b)
  181. {
  182.   twolongs r;
  183.   int bpos = (b >= 0);
  184.   unsigned ub = (bpos)? b : -b;
  185.   if ( ub >= 65536L ) {
  186.     r = (bpos)? Fix48_m_max : Fix48_m_min;
  187.     a.range_error(r);
  188.   }
  189.   else {
  190.     unsigned long 
  191.       lo_r = (a.m.l & 0xffff) * ub,
  192.       mi_r = ((a.m.l >> 16) & 0xffff) * ub,
  193.       hi_r = a.m.u * ub;
  194.     r.l = lo_r + (mi_r << 16);
  195.     r.u = hi_r + ((mi_r >> 8) & 0x00ffff00L);
  196.     if ( !bpos ) {
  197.       unsigned long l = r.l;
  198.       r.l = -r.l;
  199.       r.u = ~r.u + ((l ^ r.l) & Fix24_msb ? 0 : Fix24_lsb);
  200.     }
  201.   }
  202.   return r;
  203. }
  204.  
  205. Fix48 operator * (Fix48& a, int b)
  206. {
  207.   twolongs r;
  208.   int bpos = (b >= 0);
  209.   unsigned ub = (bpos)? b : -b;
  210.   if ( ub >= 65536L ) {
  211.     r = (bpos)? Fix48_m_max : Fix48_m_min;
  212.     a.range_error(r);
  213.   }
  214.   else {
  215.     unsigned long 
  216.       lo_r = (a.m.l & 0xffff) * ub,
  217.       mi_r = ((a.m.l >> 16) & 0xffff) * ub,
  218.       hi_r = a.m.u * ub;
  219.     r.l = lo_r + (mi_r << 16);
  220.     r.u = hi_r + ((mi_r >> 8) & 0x00ffff00L);
  221.     if ( !bpos ) {
  222.       unsigned long l = r.l;
  223.       r.l = -r.l;
  224.       r.u = ~r.u + ((l ^ r.l) & Fix24_msb ? 0 : Fix24_lsb);
  225.     }
  226.   }
  227.   return r;
  228. }
  229.  
  230. Fix48 operator << (Fix48& a, int b)
  231. {
  232.   twolongs r; r.u = r.l = 0;
  233.   if ( b >= 0 )
  234.     if ( b < 24 ) {
  235.       r.u = (a.m.u << b) + ((a.m.l >> (24 - b)) & 0xffffff00L);
  236.       r.l = a.m.l << b;
  237.     }
  238.     else if ( b < 48 ) {
  239.       r.u = a.m.l << (b - 24);
  240.     }
  241.   return r;
  242. }
  243.  
  244. Fix48 operator >> (Fix48& a, int b)
  245. {
  246.   twolongs r; r.u = r.l = 0;
  247.   if ( b >= 0 )
  248.     if ( b < 24 ) {
  249.       r.l = (a.m.u << (24 - b)) + ((a.m.l >> b) & 0xffffff00L);
  250.       r.u = (a.m.u >> b) & 0xffffff00L;
  251.     }
  252.     else if ( b < 48 ) {
  253.       r.l = (a.m.u >> (b - 24)) & 0xffffff00L;
  254.       r.u = (a.m.u >> 24) & 0xffffff00L;
  255.     }
  256.     else {
  257.       r.l = (a.m.u >> 24) & 0xffffff00L;
  258.       r.u = r.l;
  259.     }
  260.   return r;
  261. }
  262.  
  263. // error handling
  264.  
  265. void Fix24::overflow(long& i)
  266. {
  267.   (*Fix24_overflow_handler)(i);
  268. }
  269.  
  270. void Fix48::overflow(twolongs& i)
  271. {
  272.   (*Fix48_overflow_handler)(i);
  273. }
  274.  
  275. void Fix24::range_error(long& i)
  276. {
  277.   (*Fix24_range_error_handler)(i);
  278. }
  279.  
  280. void Fix48::range_error(twolongs& i)
  281. {
  282.   (*Fix48_range_error_handler)(i);
  283. }
  284.  
  285. // data definitions
  286.  
  287. Fix24_peh Fix24_overflow_handler = Fix24_overflow_saturate;
  288. Fix48_peh Fix48_overflow_handler = Fix48_overflow_saturate;
  289.  
  290. Fix24_peh Fix24_range_error_handler = Fix24_warning;
  291. Fix48_peh Fix48_range_error_handler = Fix48_warning;
  292.  
  293. //function definitions
  294.  
  295. Fix24_peh set_Fix24_overflow_handler(Fix24_peh new_handler) {
  296.   Fix24_peh old_handler = Fix24_overflow_handler;
  297.   Fix24_overflow_handler = new_handler;
  298.   return old_handler;
  299. }
  300.  
  301. Fix48_peh set_Fix48_overflow_handler(Fix48_peh new_handler) {
  302.   Fix48_peh old_handler = Fix48_overflow_handler;
  303.   Fix48_overflow_handler = new_handler;
  304.   return old_handler;
  305. }
  306.  
  307. void set_overflow_handler(Fix24_peh handler24, Fix48_peh handler48) {
  308.   set_Fix24_overflow_handler(handler24);
  309.   set_Fix48_overflow_handler(handler48);
  310. }
  311.  
  312. Fix24_peh set_Fix24_range_error_handler(Fix24_peh new_handler) {
  313.   Fix24_peh old_handler = Fix24_range_error_handler;
  314.   Fix24_range_error_handler = new_handler;
  315.   return old_handler;
  316. }
  317.  
  318. Fix48_peh set_Fix48_range_error_handler(Fix48_peh new_handler) {
  319.   Fix48_peh old_handler = Fix48_range_error_handler;
  320.   Fix48_range_error_handler = new_handler;
  321.   return old_handler;
  322. }
  323.  
  324. void set_range_error_handler(Fix24_peh handler24, Fix48_peh handler48) {
  325.   set_Fix24_range_error_handler(handler24);
  326.   set_Fix48_range_error_handler(handler48);
  327. }
  328.  
  329. void Fix24_overflow_saturate(long& i)
  330.   { i = (i > 0 ? Fix24_m_min : Fix24_m_max); }
  331. void Fix24_ignore(long&) {}
  332. void Fix24_warning(long&)
  333.   { cerr << "warning: Fix24 result out of range\n"; }
  334. void Fix24_overflow_warning_saturate(long& i)
  335.   { cerr << "warning: Fix24 result out of range\n"; 
  336.    Fix24_overflow_saturate(i); }
  337. void Fix24_abort(long&)
  338.   { cerr << "error: Fix24 result out of range\n"; abort(); }
  339.  
  340. void Fix48_ignore(twolongs&) {}
  341. void Fix48_overflow_saturate(twolongs& i)
  342.   { i = (i.u > 0 ? Fix48_m_min : Fix48_m_max); }
  343. void Fix48_warning(twolongs&)
  344.   { cerr << "warning: Fix48 result out of range\n"; }
  345. void Fix48_overflow_warning_saturate(twolongs& i)
  346.   { cerr << "warning: Fix48 result out of range\n"; 
  347.    Fix48_overflow_saturate(i); }
  348. void Fix48_abort(twolongs&)
  349.   { cerr << "error: Fix48 result out of range\n"; abort(); }
  350.  
  351.